﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;

using SinsMapPacker;

namespace SinsMapPacker.CLI
{

class App
{
    private static StringDictionary args;
    private static StringCollection extraArgs;

    public static void Main(string[] args)
    {
        if (args.Length < 1)
        {
            PrintUsage();
            return;
        }

        try
        {
            ProcessCmdLine(args);
        }
        catch (ApplicationException e)
        {
            PrintUsage(e.Message);
        }
    }

    private static void ProcessCmdLine(string[] cmdLineArgs)
    {
        if (cmdLineArgs.Length < 2)
            throw new ApplicationException("No map pack file specified");

        args = new StringDictionary();
        args["cmd"]      = cmdLineArgs[0];
        args["map pack"] = cmdLineArgs[1];
        extraArgs        = new StringCollection();
        for (var i = 2; i < cmdLineArgs.Length; i++)
            extraArgs.Add(cmdLineArgs[i]);

        switch (args["cmd"])
        {
            case "create":
                CmdCreate();
                break;
            
            case "add":
                CmdAdd();
                break;

            case "remove":
                CmdRemove();
                break;

            case "list":
                CmdList();
                break;

            case "unpack":
                CmdUnpack();
                break;

            default:
                throw new ApplicationException(string.Format("Unknown command: '{0}'", args["cmd"]));
        }

    }

    private static void CmdCreate()
    {
        if (args["map pack"].Length == 0)
            throw new ApplicationException("No filename specified");
        
        if (File.Exists(args["map pack"]))
            throw new ApplicationException(
                string.Format("'{0}' already exists. Remove it first.", args["map pack"]));

        Console.WriteLine("Creating new map pack '{0}'", args["map pack"]);

        var mapPack = new MapPack();
        mapPack.Write(args["map pack"]);
    }

    private static void CmdAdd()
    {
        var mapPack = OpenMapPack();

        if (extraArgs.Count == 0)
            throw new ApplicationException("No filename(s) specified");

        foreach (var file in extraArgs)
        {
            if (!File.Exists(file))
                throw new ApplicationException(
                    string.Format("'{0}' does not exist", file));
            
            Console.WriteLine("Adding file '{0}' to map pack '{1}'",
                file, args["map pack"]);
            
            mapPack.AddFile(file);
        }

        mapPack.Write(args["map pack"]);
    }

    private static void CmdRemove()
    {
        var mapPack = OpenMapPack();

        if (extraArgs.Count == 0)
            throw new ApplicationException("No filename specified");

        Console.WriteLine("Removing file '{0}' from map pack '{1}'",
            extraArgs[0], args["map pack"]);

        mapPack.RemoveFile(extraArgs[0]);

        mapPack.Write(args["map pack"]);
    }

    private static void CmdList()
    {
        var mapPack = OpenMapPack();
        Console.WriteLine("Listing contents of map pack '{0}':", args["map pack"]);

        foreach (string dir in mapPack.Directories)
            foreach (string file in mapPack.Files(dir))
                Console.WriteLine("{0}/{1}", dir, file);
    }

    private static void CmdUnpack()
    {
        var mapPack = OpenMapPack();

        var targetDir = (extraArgs.Count == 0) ? "./" : extraArgs[0];

        Console.WriteLine("Unpacking map pack '{0}' to '{1}'", args["map pack"], targetDir);

        mapPack.Unpack(targetDir);
    }

    private static MapPack OpenMapPack()
    {
        if (!File.Exists(args["map pack"]))
            throw new ApplicationException(
                string.Format("Map pack file '{0}' foes not exist", args["map pack"]));

        return MapPack.Open(args["map pack"]);
    }

    private static void PrintUsage(string msg)
    {
        if (msg.Length > 0)
            Console.WriteLine(msg);
        Console.Write(@"
Usage: test <command> <map pack> [<argument>]

Available commands:

    create      Creates a new empty map pack <map pack>. <map pack> must not
                exist.

    list        Lists the contents of a Sins map pack.

    unpack      Unpacks the map pack to the directory specified by <argument>
                in the second argument, or to the current directory if none
                is specified.

    add         Adds the file specified in <argument> to <map pack>.

    remove      Removes the file specified in <argument> from <map pack>.
");
    }

    private static void PrintUsage()
    {
        PrintUsage("");
    }

}

}